package com.kingmed.kmss.common.compare;

import com.kingmed.kmss.common.annotation.FieldCompare;
import com.kingmed.kmss.common.constant.common.OperatorConstants;
import com.kingmed.kmss.common.utils.StringUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author rain
 * @date 2023/3/1 15:51
 */
public class SerializableFieldCompare {

    /**
     * demo: entity.field 增加注解（properties支持字典对照）：
     * @FieldCompare(chineseName = "项目类型", properties = "1:医检项目,2:金至项目,3:司法鉴定项目,4:合同科研项目,5:KMCT项目,6:其他项目")
     * @param type
     * @param newObject
     * @param oldObject
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> List<String> compare (Class<T> type, T newObject, T  oldObject ) throws Exception {
        List<String> logList = new ArrayList<>();
        Class<?> newObj = newObject.getClass();
        Class<?> oldObj = oldObject.getClass();
        Field[] newFields = type.getDeclaredFields();
        for (int i = 0; i < newFields.length; i++) {
            FieldCompare newAnnotation = newFields[i].getAnnotation(FieldCompare.class);
            if(null != newAnnotation){
                PropertyDescriptor newPd = new PropertyDescriptor(newFields[i].getName(), newObj);
                Method getMethodNew = newPd.getReadMethod();
                Object oldVal = getMethodNew.invoke(oldObject);
                Object newVal = getMethodNew.invoke(newObject);
                boolean eq = false;
                if (oldVal instanceof String){
                    String s1 = checkString(oldVal);
                    String s2 = checkString(newVal);
                    eq = !s1.equals(s2);
                }else if(oldVal instanceof Integer){
                    int i1 = (Integer) oldVal;
                    int i2 = (Integer) newVal;
                    eq = i1 != i2;
                }else if(oldVal instanceof Double){
                    double d1 = (Double) oldVal;
                    double d2 = (Double) newVal;
                    eq = d1 != d2;
                }else if(oldVal instanceof BigDecimal){
                    BigDecimal b1 = (BigDecimal) oldVal;
                    BigDecimal b2 = (BigDecimal) newVal;
                    eq = b1.compareTo(b2) != 0;
                }else if(oldVal instanceof Long){
                    long l1 = (Long) oldVal;
                    long l2 = (Long) newVal;
                    eq = l1 != l2;
                }
                String s1 = checkString(oldVal);
                String s2 = checkString(newVal);
                if (eq) {
                    Map<String, String> map = codeToNameMap(newAnnotation);
                    if (map.size() > 0) {
                        logList.add(newAnnotation.chineseName() + "由：[" + getMultiSelectName(s1, map) + "]更改为了[" + getMultiSelectName(s2, map) + "]");
                    }else {
                        logList.add(newAnnotation.chineseName() + "由：[" + s1 + "]更改为了[" + s2 + "]");
                    }
                }
            }
        }
        return logList;
    }

    private static Map<String,String> codeToNameMap(FieldCompare newAnnotation){
        Map<String,String> map = new HashMap<>();
        String properties = newAnnotation.properties();
        if(StringUtils.isNotBlank(properties)){
            String[] propertiesArr = properties.split(",");
            for (String propertie : propertiesArr) {
                String[] split = propertie.split(":");
                map.put(split[0],split[1]);
            }
        }
        return map;
    }

    private static String checkString(Object obj){
        String str = (obj==null) ? "" : obj.toString().trim();
        if (str.equals("null")){
            str = "";
        }
        if (str.indexOf("@_@")!=-1) {
            str = str.replaceAll("@_@", OperatorConstants.DH_KEY);
        }
        return str;
    }

    /**
     * 切割处理下拉多选的key-value翻译（暂时只支持分隔符为","的情况）
     * @param value
     * @param map
     * @return
     */
    private static String getMultiSelectName(String value, Map<String, String> map){
        String str = value;
        if (StringUtils.isNotEmpty(value)){
            if (value.indexOf(OperatorConstants.DH_KEY)!=-1) {
                String[] split = value.split(OperatorConstants.DH_KEY);
                str = Arrays.stream(split).map(p -> map.get(p)).collect(Collectors.joining(OperatorConstants.DH_KEY));
            }else{
                str = map.get(value);
            }
        }
        return str;
    }
}
